/*
 *    This file is part of BlobDB.
 *
 *    BlobDB is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    BlobDB is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with BlobDB.  If not, see <http://www.gnu.org/licenses/>.
 *    
 *    Copyright(c) 2011 Michael Kankkonen
 *    http://www.vnetcon.org
 */


package org.vnetcon.blobdb.database;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.vnetcon.blobdb.database.util.ColumnInfo;
import org.vnetcon.blobdb.database.util.TableRow;
import org.vnetcon.xml.ws.servlet.ToXmlInterface;

/**
 * This is the return class from statement when executing queries.
 *
 */
@XmlRootElement
@XmlType(name="ResultSet")
public class ResultSet {

	StringBuilder sb = new StringBuilder();
	private int iResults = 0;
	private int iCursor = 0;
//	private byte[][] dataRows = null;
//	private String[] rowid = null;
//	private ResultSet[][] subQueries = null;
//	private ColumnInfo ci = null;
	private long lExecutionTime = -1;
	private String statusMessage = "ok:";
	List<String> selectCols = new ArrayList<String>();

//	ArrayList<Result> results = null;
	List<Result> results = null;
	
	// this is here because of schemagen - it requires this kind of constructor
	/**
	 * This constructor is not ment to be used by end users. This is here
	 * only because of creating WebService classes to be returned.
	 * If this constructor is missing then schemagen schema generation fails.
	 * 
	 */
	public ResultSet(){
	}
	
	public List<String> getSelectCols() {
		return selectCols;
	}

	public void setSelectCols(List<String> selectCols) {
		this.selectCols = selectCols;
	}

	public void finalize(){
		results = null;
		Runtime.getRuntime().gc();
	}
	
	
	/**
	 * This is for BlobDB. This will be set after the execution is completed.
	 * 
	 * @param execTime
	 */
	public void setExecutionTime(long execTime){
		this.lExecutionTime = execTime;
	}

	/**
	 * This is mainly for WebService calls to give information
	 * of what have happen on server side. 
	 * 
	 * @param statusMessage
	 */
	public void setStatusMessage(String statusMessage){
		this.statusMessage = statusMessage;
	}

	/**
	 * This is the first thing client side of WebService call should check.
	 * If this value starts with "error:" then the execution on serverside have failed.
	 * 
	 * @return
	 */
	public String getStatusMessage(){
		return this.statusMessage;
	}

	/**
	 * This is also for WebService clients. With this client side can iterate through results
	 * after executing the web service call. 
	 * 
	 * These WebService classes are here so that the actual return class can be generated
	 * from the same ResultSet that is used by "native java code". 
	 * 
	 * @return
	 */
	public List<Result> getResults(){
		return this.results;
	}

	/**
	 * BlobDB uses this method to set results to ResultSet.
	 * 
	 * @param results
	 */
	public void setResults(List<Result> results){
//	public void setResults(ArrayList<Result> results){
		this.iResults = results.size();
		iCursor--;
		this.results = results;
	}
	// webservice calls end


	public int getRowCount(){
		return this.iResults;
	}
	
	public long getExecutionTime(){
		return this.lExecutionTime;
	}

	/**
	 * This is the main method to be used when iterating through results.
	 * 
	 * @return
	 */
	public boolean next(){
		if(iCursor + 1 < iResults){
			iCursor++;
			return true;
		}else{
			return false;
		}
	}

	/**
	 * This will reset the result set cursor back to start. After this it is possible
	 * to iterate the results again using next().
	 * 
	 */
	public void resetCursor(){
		this.iCursor = -1;
	}

	/**
	 * This is the recommended way to get values out from result set.
	 * Please note that BlobDB use only string values when handling data.
	 * 
	 * @param colName
	 * @return
	 * @throws SQLException
	 */
	public String getString(String colName) throws SQLException {
		Result r = this.results.get(iCursor);
		return r.getColumnValues().get(colName);
	}

	public String getString(int colIndex) throws SQLException {
		String colName = this.selectCols.get(colIndex - 1);
		return this.getString(colName);
	}
	
	
	/**
	 * This will return the result's rowid (BlobDB signs every row with unique id).
	 * 
	 * @return
	 * @throws SQLException
	 */
	public String getRowid() throws SQLException {
		Result r = this.results.get(iCursor);
		return r.getRowid();
	}

	/**
	 * In BlobDB it is possible to do sub selects in sql statements select part.
	 * For example: SELECT LNAME, SUB [sql] END, FNAME FROM TEST.USER WHERE LNAME == 'Smith';
	 * The sub select is returned as ResultSet and it can contain 1-n rows depending on result.
	 * 
	 * @param index
	 * @return
	 * @throws SQLException
	 */
	public ResultSet getSubQuery(int index) throws SQLException {
		return this.results.get(iCursor).getSubqueries().get(index);
	}

	
	public StringBuilder toXML(){
		int i = 0;
		sb.append("<executionTime>");
		sb.append(this.lExecutionTime);
		sb.append("</executionTime>");
		if(this.results != null){
			while (i < this.results.size()) {
				sb.append("<results>");
				sb.append(this.results.get(i).toXML());
				sb.append("</results>");
				i++;
			}
		}
		i = 0;
		while(i < this.selectCols.size()){
			sb.append("<selectCols>");
//			sb.append("<value>");
			sb.append(this.selectCols.get(i));
//			sb.append("</value>");
			sb.append("</selectCols>");
			i++;
		}		
		sb.append("<statusMessage>");
		sb.append(this.statusMessage);
		sb.append("</statusMessage>");
		return sb;
	}

		
}
